#include "cpu/exec/template-start.h"
#include "memory/tlb.h"
#include "cpu/decode/modrm.h"

#define instr mov

static void do_execute() {
	OPERAND_W(op_dest, op_src->val);
	print_asm_template2();
}

make_instr_helper(i2r)
make_instr_helper(i2rm)
make_instr_helper(r2rm)
make_instr_helper(rm2r)

make_helper(concat(mov_a2moffs_, SUFFIX)) {
	swaddr_t addr = instr_fetch(eip + 1, 4);
	current_sreg = R_DS;  //A0,A1用DS
	MEM_W(addr, REG(R_EAX));
	print_asm("mov" str(SUFFIX) " %%%s,0x%x", REG_NAME(R_EAX), addr);
	return 5;
}

make_helper(concat(mov_moffs2a_, SUFFIX)) {
	swaddr_t addr = instr_fetch(eip + 1, 4);
	current_sreg = R_DS; //A2,A3用DS
	REG(R_EAX) = MEM_R(addr);
	print_asm("mov" str(SUFFIX) " 0x%x,%%%s", addr, REG_NAME(R_EAX));
	return 5;
}

#if DATA_BYTE == 4

make_helper(mov_r2cr){
	//Log("eip:%x %x",eip,instr_fetch(eip,1));
	//Log("cpu.eip:%x %x",cpu.eip,instr_fetch(cpu.eip,1));

	// Log("mov_r2cr: from 0x100000:");
	// Log("0x100000 %x",instr_fetch(0x100000,1));
	// Log("0x100001 %x",instr_fetch(0x100001,1));
	// Log("0x100002 %x",instr_fetch(0x100002,1));
	// Log("0x100003 %x",instr_fetch(0x100003,1));
	// Log("0x100004 %x",instr_fetch(0x100004,1));
	// Log("0x100005 %x",instr_fetch(0x100005,1));
	// Log("0x100006 %x",instr_fetch(0x100006,1));
	// Log("0x100007 %x",instr_fetch(0x100007,1));
	// Log("0x100008 %x",instr_fetch(0x100008,1));
	// Log("0x100009 %x",instr_fetch(0x100009,1));
    // Log("0x10000a %x",instr_fetch(0x10000a,1));
    // Log("0x10000b %x",instr_fetch(0x10000b,1));
    // Log("0x10000c %x",instr_fetch(0x10000c,1));
    // Log("0x10000d %x",instr_fetch(0x10000d,1));
	// Log("0x10000e %x",instr_fetch(0x10000e,1));
    // Log("0x10000f %x",instr_fetch(0x10000f,1));
	// Log("0x100010 %x",instr_fetch(0x100010,1));
	// Log("0x100011 %x",instr_fetch(0x100011,1));
	// Log("0x100012 %x",instr_fetch(0x100012,1));
	// Log("0x100013 %x",instr_fetch(0x100013,1));
	// Log("0x100014 %x",instr_fetch(0x100014,1));
	// Log("0x100015 %x",instr_fetch(0x100015,1));
	// Log("0x100016 %x",instr_fetch(0x100016,1));
	// Log("0x100017 %x",instr_fetch(0x100017,1));

	//取出ModRM字节
	uint8_t ModRM = instr_fetch(eip + 1,1);
	//取出CR寄存器编号
	uint8_t cr_num = (ModRM >> 3) & 7; // reg
	//取出寄存器编号
	uint8_t reg_num = ModRM & 7; // r/m
	switch (cr_num){
		case 0:
			cpu.cr0.val = reg_l(reg_num);//32位
			//printf("11??\n");
			//print_asm("mov %s CR0",REG_NAME(reg_num));
			//Assert(0,"??");
			break;
		case 3:
			//CR3存储当前进程的页表基址
			//切换页表时，要刷新TLB(页表的缓存)，以防止使用旧的条目
			init_tlb();
			cpu.cr3.val = reg_l(reg_num);
			//print_asm("mov %s CR3",REG_NAME(reg_num));
			break;
		default:
			break;
	}
	//Assert(0,"??");
	print_asm("mov %s cr%d",REG_NAME(reg_num),cr_num);
	//cpu.eip++;
	return 2; //处理的指令字节数,前面的0F已被跳过了
}

make_helper(mov_cr2r){
	//Log("eip:%x %x",eip,instr_fetch(eip,1));

	//取出ModRM字节
	uint8_t ModRM = instr_fetch(eip + 1,1);
	//printf("0x%x\n",ModRM);
	//取出CR寄存器编号
	uint8_t cr_num = (ModRM >> 3) & 7; // reg
	//取出寄存器编号
	uint8_t reg_num = ModRM & 7; // r/m
	//printf("cr_num:%d\n",cr_num);
	switch (cr_num){
		case 0:
			//reg_l是宏不是函数，会在预处理阶段替换为对应代码片段，所以这里作为dest可以修改寄存器的数值
			reg_l(reg_num) = cpu.cr0.val;
			//printf("22??\n");
			//print_asm("mov CR0 %s",REG_NAME(reg_num));
			break;
		case 3:
			reg_l(reg_num) = cpu.cr3.val;
			//print_asm("mov CR3 %s",REG_NAME(reg_num));
			break;
		default:
			break;
	}
	print_asm("mov cr%d %s",cr_num,REG_NAME(reg_num));
	return 2; //处理的指令字节数
}


#endif

#if DATA_BYTE == 2
make_helper(mov_rm2sreg){
	//取出ModRM字节
	uint8_t ModRM = instr_fetch(eip + 1,1);
	//取出段寄存器编号
	uint8_t sreg_num = ((ModRM >> 3) & 7); // reg
	//取出寄存器编号
	uint8_t reg_num = (ModRM & 7); // r/m
	//将新的段描述符储存到段寄存器中
	cpu.sreg[sreg_num].selector = reg_w(reg_num);
	
	sreg_load(sreg_num);
	print_asm("mov %s SREG[%u]",REG_NAME(reg_num),sreg_num);
	//Log("?");
	return 2;
}
#endif


#include "cpu/exec/template-end.h"
